package com.github.xzb617.adm.service.impl;

import com.github.xzb617.adm.dao.ConfigFileMapper;
import com.github.xzb617.adm.dao.ConfigGroupMapper;
import com.github.xzb617.adm.service.ConfigFileService;
import com.github.xzb617.adm.service.ConfigReleaseService;
import com.github.xzb617.client.config.ClientsTransmitter;
import com.github.xzb617.client.config.key.ClientKeyType;
import com.github.xzb617.domain.dto.ConfigFileDTO;
import com.github.xzb617.domain.entity.ConfigFile;
import com.github.xzb617.domain.entity.ConfigGroup;
import com.github.xzb617.except.ServiceException;
import com.github.xzb617.security.SubjectHolder;
import com.github.xzb617.utils.DigestUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.List;

@Service
public class ConfigFileServiceImpl implements ConfigFileService {

    private final ConfigFileMapper configFileMapper;
    private final ConfigGroupMapper configGroupMapper;
    private final ConfigReleaseService configReleaseService;
    private final ClientsTransmitter clientsTransmitter;

    public ConfigFileServiceImpl(ConfigFileMapper configFileMapper, ConfigGroupMapper configGroupMapper, ConfigReleaseService configReleaseService, ClientsTransmitter clientsTransmitter) {
        this.configFileMapper = configFileMapper;
        this.configGroupMapper = configGroupMapper;
        this.configReleaseService = configReleaseService;
        this.clientsTransmitter = clientsTransmitter;
    }

    @Override
    public ConfigFile getById(Integer id) {
        return this.configFileMapper.selectById(id);
    }

    @Override
    public ConfigFile getByName(String name) {
        Example example = new Example(ConfigFile.class);
        example.createCriteria()
                .andEqualTo("configName", name);
        return this.configFileMapper.selectOneByExample(example);
    }

    @Override
    public ConfigFile getByClient(String configGroupName, String configFileName) {
        return this.configFileMapper.selectByClient(configGroupName, configFileName);
    }

    @Override
    public List<ConfigFile> getList(Integer configGroupId) {
        Example example = new Example(ConfigFile.class);
        example.createCriteria()
                .andEqualTo("configGroupId", configGroupId);
        return this.configFileMapper.selectByExample(example);
    }

    @Override
    @Transactional
    public void save(ConfigFileDTO dto) {
        // 判断配置文件名称是否已被使用
        String configName = dto.getConfigName();
        Integer configGroupId = dto.getConfigGroupId();
        ConfigFile var1 = this.getByName(configName);
        if (var1!=null && var1.getConfigGroupId()==configGroupId) {
            throw new ServiceException("配置文件名称已被使用");
        }
        // 赋值
        var1 = new ConfigFile();
        BeanUtils.copyProperties(dto, var1);
        var1.setCreateTime(new Date());
        var1.setCreateUser(SubjectHolder.getContext().getUsername());
        var1.setStatus(false);
        this.configFileMapper.insertSelective(var1);
        // 数量 +1
        this.changeFileCountInGroup(configGroupId, 1);
    }

    @Override
    @Transactional
    public void update(ConfigFileDTO dto) {
        // 判断是否存在配置文件
        ConfigFile var1 = this.getById(dto.getId());
        if (var1 == null) {
            throw new ServiceException("配置文件不存在");
        }
        // 计算sign
        String configContent = dto.getConfigContent();
        String sign = null;
        if (!StringUtils.isEmpty(configContent)) {
            sign = DigestUtil.md5(configContent, "utf-8");
        }
        // 更新配置内容、Sign签名、发布状态
        var1.setConfigContent(configContent);
        var1.setStatus(false);
        var1.setSign(sign);
        var1.setRemark(dto.getRemark());
        var1.setUpdateTime(new Date());
        var1.setUpdateUser(SubjectHolder.getContext().getUsername());
        this.configFileMapper.updateByPrimaryKeySelective(var1);
    }

    @Override
    @Transactional
    public void release(ConfigFileDTO dto) {
        // 判断是否存在配置文件
        ConfigFile var1 = this.getById(dto.getId());
        if (var1 == null) {
            throw new ServiceException("配置文件不存在");
        }
        // 判断是否是未发布状态
        Boolean status = var1.getStatus();
        if (Boolean.TRUE.equals(status)) {
            throw new ServiceException("配置文件不是未发布状态，无法进行发布操作");
        }
        // 更新发布状态
        var1.setStatus(true);
        var1.setReleaseTime(new Date());
        var1.setReleaseUser(SubjectHolder.getContext().getUsername());
        this.configFileMapper.updateByPrimaryKeySelective(var1);

        // 生成一份历史快照记录
        this.configReleaseService.releaseHistory(var1);

        // 通知客户端有配置文件更新
        String clientId = var1.getConfigGroupName() + ":" + var1.getConfigName();
        this.clientsTransmitter.transmitClient(ClientKeyType.CONFIG, clientId);
    }

    @Override
    @Transactional
    public void delete(Integer id) {
        // 判断是否存在配置文件
        ConfigFile var1 = this.getById(id);
        if (var1 == null) {
            throw new ServiceException("配置文件不存在");
        }
        // 删除
        this.configFileMapper.deleteByPrimaryKey(id);
        // 数量 -1
        this.changeFileCountInGroup(var1.getConfigGroupId(), -1);
    }

    @Override
    @Transactional
    public void deleteByGroup(Integer configGroupId) {
        Example example = new Example(ConfigFile.class);
        example.createCriteria()
                .andEqualTo("configGroupId", configGroupId);
        this.configFileMapper.deleteByExample(example);
    }

    @Transactional
    public void changeFileCountInGroup(Integer groupId, int count) {
        ConfigGroup configGroup = this.configGroupMapper.selectByPrimaryKey(groupId);
        if (configGroup == null) {
            throw new ServiceException("所属配置分组不存在或已被删除");
        }
        configGroup.setConfigFileCount(configGroup.getConfigFileCount() + count);
        this.configGroupMapper.updateByPrimaryKeySelective(configGroup);
    }
}
